package com.garbuz.svnadmin.model;

import com.garbuz.svnadmin.SvnModelError;
import com.garbuz.svnadmin.data.Group;
import com.garbuz.svnadmin.data.Permission;
import com.garbuz.svnadmin.data.Repo;
import com.garbuz.svnadmin.data.User;
import common.utils.FileUtil;
import org.ini4j.Ini;
import org.ini4j.Profile;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class SvnModelWriter
{
	private SvnModel model;

	public SvnModelWriter(SvnModel model)
	{
		super();
		this.model = model;
	}

	public void write(String passwordPath, String authzPath) throws Exception
	{
		writePasswordsFile(passwordPath);
		writeAuthFile(authzPath);
	}

	private void writeAuthFile(String path) throws Exception
	{
		Ini authFile = new Ini();
		writeGroups(authFile);
		writePermissions(authFile);

		String tempPath = path.concat(".svnadmin.temp");
		authFile.store(new File(tempPath));
		renameFile(tempPath, path);
	}
	
	private void writePermissions(Ini authFile)
	{
		for (Repo repo: model.getRepos())
		{
			writeRepoPermissions(repo, authFile);
		}
	}

	private void writeRepoPermissions(Repo repo, Ini authFile)
	{
		String sectionName = repo.name.concat(":/");
		Profile.Section section = authFile.add(sectionName);
		
		if (repo.permissions.size() == 0)
			repo.addDefaultPermissions();

		for (Permission permission : repo.permissions)
		{
			String key = permission.isGroup
					? "@".concat(permission.name)
					: permission.name;
			String value = permission.readonly
					? "r"
					: "rw";
			section.put(key, value);
		}
	}

	private void writeGroups(Ini authFile)
	{
		Profile.Section section = authFile.add("groups");
		section.put(Group.ALL_NAME, getUserNames(model.getUsers()));

		for (Group group: model.getGroups())
		{
			List<User> users = model.getUsersInGroup(group.name);
			section.put(group.name, getUserNames(users));
		}
	}

	private void writePasswordsFile(String path) throws Exception
	{
		List<String> rows = new ArrayList<String>();
		for (User user : model.getUsers())
		{
			rows.add(user.name.concat(":{SHA}").concat(user.hash));
		}

		String tempPath = path.concat(".svnadmin.temp");
		FileUtil.StringListToFile(tempPath, rows);
		renameFile(tempPath, path);
	}

	private void renameFile(String sourcePath, String targetPath) throws SvnModelError
	{
		if (!FileUtil.renameFile(sourcePath, targetPath))
			throw new SvnModelError("Cannot write file:\n" + targetPath);
	}

	private String getUserNames(Iterable<User> users)
	{
		StringBuilder result = new StringBuilder();
		boolean needComma = false;

		for (User user: users)
		{
			if (needComma)
				result.append(",");

			result.append(user.name);
			needComma = true;
		}

		return result.toString();
	}
}
